Repository navigation
perf(query): evaluate CONTAINS, STARTS WITH, ENDS WITH with Arrow kernels - #148
Merged
Merged
Conversation
…nels The string predicate UDF broadcast a literal search string to a full array and called str::contains per row, building a new substring searcher each time. Call Arrow's contains/starts_with/ends_with kernels instead: a literal stays a scalar and one searcher serves the batch. These are the kernels DataFusion's LIKE and contains() use. Bound parameters, null and non-string operands keep their Cypher semantics. Fixes #146
Deploying lance-csr with
|
| Latest commit: |
d7dfe35
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://d988ea81.lance-csr.pages.dev |
| Branch Preview URL: | https://perf-native-string-predicate.lance-csr.pages.dev |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #146.
Problem
Since #120,
CONTAINS,STARTS WITHandENDS WITHrun through the__string_*UDF, which handles bound parameters,%/_/\and Cypher's null for non-string operands. But it evaluated row by row. It broadcast a literal search string into an array as long as the batch, then calledstr::containsper row, which builds a new substring searcher each time. On LDBC that madeCONTAINSfilters up to about 2x slower than 0.7.0'sLIKE.Change
The UDF keeps its place in the plan and its semantics. Its body now calls Arrow's
contains/starts_with/ends_withkernels, the ones DataFusion'sLIKEandcontains()use. A literal or parameter pattern stays a scalar, and one searcher serves the whole batch. A column pattern (a.name CONTAINS b.name) still goes row by row through the same kernels. Plans andexplain()output are unchanged.Tests
test_string_parameters.py; the existing cases there cover%,_,\, non-ASCII, empty, null and non-string patterns, for both join and CSR plans.make install && uv run --no-sync pytest(1,714 passed),cargo test -p lance-csr --lib,cargo clippy -p lance-csr --all-targets -- -D warnings.Benchmarks
Release wheels from
main(45841ad) and this branch (d7dfe35), run with the CONTRIBUTING harness, alternating main/branch, two runs each (three for complex/memory, see below). Apple silicon, plugged in. Every run passed its answer checks.Eight queries in this suite use
CONTAINS. The gains are in three of them: Q5 −25% (memory) / −36% (lazy) and Q20 −40% / −29%, the two queries from the issue, and Q19 −8% / −10%. The other five (Q2, Q6, Q8, Q16, Q29) and the rest of the suite are within noise.Note on complex/memory: no query in that suite uses
CONTAINS,STARTS WITHorENDS WITH, so this change doesn't reach it. Q7 (+20%) and Q9 (+26%) come from one branch run (0004) with interference. Its Q7 mean was 16.2 ms against a median of 10.0 ms, and Q9's 72.5 ms against 49.5 ms. The other two branch runs match main: Q7 at 9.7 and 10.0 ms against main's 9.8 to 10.1 ms, and Q9 at 42.7 and 44.8 ms against main's 40.9 to 43.6 ms. The table below averages all three runs, outlier included.The issue's synthetic reproducer (1M rows, medians of 15 runs, two rounds):
CONTAINS, 2 wordsCONTAINS, 20 wordsSTARTS WITH/ENDS WITH, 2 wordsSTARTS WITH/ENDS WITH, 20 wordsCONTAINSon short strings is back near 0.7.0's 1.4 ms.Every query (mean of runs; "main run gap" is the difference between the first and last main runs)
graph-benchmark-ldbc, memory (2 main runs, 2 branch runs)
Geomean ratio branch/main: 0.962 (-3.8%) over 30 queries
graph-benchmark-ldbc, lazy (2 main runs, 2 branch runs)
Geomean ratio branch/main: 0.966 (-3.4%) over 30 queries
graph-benchmark-ldbc-complex, memory (3 main runs, 3 branch runs)
Geomean ratio branch/main: 1.039 (+3.9%) over 14 queries
graph-benchmark-ldbc-complex, lazy (2 main runs, 2 branch runs)
Geomean ratio branch/main: 1.006 (+0.6%) over 14 queries
🤖 Generated with Claude Code